#pragma once

#include <iostream>
#include <memory>
#include <vector>
#include "Socket.hpp"
#include <poll.h>
const static int gsize = sizeof(fd_set) * 8;
const static int gdefault = -1;
class PollServer
{
public:
    PollServer(uint16_t port)
        : _lintensocket(std::make_unique<TcpSocket>())
    {
        _lintensocket->BuildListenSocketMethod(port);
        for (int i = 0; i < gsize; i++)
        {
            _fdv[i].fd = gdefault;
            _fdv->events = _fdv->revents = 0;
        }
        _fdv[0].fd = _lintensocket->GetSockFd();
        _fdv[0].events = POLLIN;
    }

    void Accept()
    {
        InetAddr clientaddr;
        int sockfd = _lintensocket->Accept(&clientaddr);
        if (sockfd > 0)
        {
            LOG(LogLevel::INFO) << "get new sockfd : " << sockfd << ", client addr : " << clientaddr.ToString();
        }
        else
        {
            perror("socket");
        }

        // 新的sockfd 交给 poll
        int pos = 0;
        for (; pos < gsize; pos++)
        {
            if (_fdv[pos].fd == gdefault)
            {
                _fdv[pos].fd = sockfd;
                _fdv[pos].events = POLLIN;
                break;
            }
        }
        if (pos == gsize)
        {
            LOG(LogLevel::WARNING) << "server is full !";
            close(sockfd);

            // 扩容
        }
    }

    void Recver(int index)
    {
        int sockfd = _fdv[index].fd;
        char buffer[1024];
        ssize_t n = recv(sockfd, buffer, sizeof(buffer), 0);
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "client say# " << buffer << std::endl;
            std::string echo_string = "server echo# ";
            echo_string += buffer;
            send(sockfd, echo_string.c_str(), echo_string.size(), 0);
        }
        else if (n == 0)
        {
            LOG(LogLevel::ERROR) << "client quit " << _fdv[index].fd;
            _fdv[index].fd = gdefault;
            _fdv[index].events = _fdv[index].revents = 0;
            close(sockfd);
        }
        else
        {
            _fdv[index].fd = gdefault;
            _fdv[index].events = _fdv[index].revents = 0;
            close(sockfd);
            LOG(LogLevel::ERROR) << "recv error";
        }
    }

    void EventDispatcher()
    {
        for (int i = 0; i < gsize; i++)
        {
            if (_fdv[i].fd == gdefault)
            {
                continue;
            }
            if (_fdv[i].revents & POLLIN)
            {
                if (_fdv[i].fd == _lintensocket->GetSockFd())
                {
                    Accept();
                }
                else
                {
                    Recver(i);
                }
            }
            // else if(FD_ISSET(_fdv[i], &wfds))
            // {

            // }
        }
    }

    void Run()
    {
        while (true)
        {
            //  就绪事件通知机制
            int timeout = 1000;
            int n = poll(_fdv, gsize, timeout);
            switch (n)
            {
            case 0:
                LOG(LogLevel::DEBUG) << "time out...: ";
                break;
            case -1:
                LOG(LogLevel::ERROR) << "select error";
                break;
            default:
                EventDispatcher();
                break;
            }
        }
    }
    ~PollServer()
    {
    }

private:
    std::unique_ptr<Socket> _lintensocket;

    struct pollfd _fdv[gsize];
};